package com.zwx.algorithms.demo;/*
 * Copyright (C), weixin.zhu
 * FileName: Demo
 * Author:   weixin.zhu
 * Date:     2020/12/16 18:23
 * Description: demo
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */

import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.HashSet;

/**
 * 〈一句话功能简述〉<br>
 * 〈demo〉
 *
 * @author weixin.zhu
 * @create 2020/12/16
 */
public class HashDemo {
    static final Logger log = LoggerFactory.getLogger(HashDemo.class);

    private String name;
    private Integer age;

    public HashDemo() {
    }

    public HashDemo(String name, Integer age) {
        this.name = name;
        this.age = age;
    }


    public int hashCode() {
        int result = 17;
        result = 31 * result + (name == null ? 0 : name.hashCode());
        result = 31 * result + (age == null ? 0 : age.hashCode());
        return result;

    }

    /**
     * 模拟hashmap中的hash方法，再次散列<br>
     * 通过对key的hashcode右移16位后，与key自身hashcode进行按位异或计算，作为最终的hashcode
     *
     * @param key, HashMap的key对象
     * @return int 返回再次hash的结果
     * @author weixin.zhu
     * @create 2020/12/17 15:37
     * @since 1.0.0
     */
    static int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }


    /**
     * 模拟hashmap用hashcode计算将要存储的数组下标<br>
     * 用hashmap存储的数组大小-1后，和hashcode进行按位与运算，
     * 按位与操作的规则是：仅当两个操作数都为1时。输出结果才为1。否则为0
     *
     * @param size Hashmap中数组当前元素个数
     * @param hashcode HashMap的key的最终hashcode
     * @return int
     * @author weixin.zhu
     * @create 2020/12/17 15:31
     * @since 1.0.0
     */
    static int calcHashMapTableIndex(int size, int hashcode) {
        return (size - 1) & hashcode;
    }

    static void calcHashMapKeyTest() {
        int size = 16;
        HashDemo obj = new HashDemo("weixin",36);
        int key = obj.hashCode();
        log.debug("binaryString:{},hashcode:{}", StrUtil.fillBefore(Integer.toBinaryString(key), '0', 32), key);
        log.debug("binaryString:{},hashcode>>>16:{}", StrUtil.fillBefore(Integer.toBinaryString(key >>> 16), '0', 32), key >>> 16);
        log.debug("binaryString:{},hashcode ^ (hashcode>>>16):{}", StrUtil.fillBefore(Integer.toBinaryString(key ^ (key >>> 16)), '0', 32), key ^ (key >>> 16));
        log.debug("binaryString:{},HashDemo.hash:{}", StrUtil.fillBefore(Integer.toBinaryString(HashDemo.hash(obj)), '0', 32), HashDemo.hash(obj));
        log.debug("binaryString:{},size-1:{}", StrUtil.fillBefore(Integer.toBinaryString(size - 1), '0', 32), size - 1);
        log.debug("binaryString:{},cashHashMapTableIndex:{}", StrUtil.fillBefore(Integer.toBinaryString(calcHashMapTableIndex(size, HashDemo.hash(obj))), '0', 32), calcHashMapTableIndex(size, HashDemo.hash(obj)));
    }

    @SuppressWarnings(value={"unchecked", "rawtypes","unused"})
    public static void main(String[] args) {
        HashDemo.calcHashMapKeyTest();
        HashMap a = new HashMap();
        HashSet b = new HashSet();


        System.out.println(b.add("a"));
        System.out.println(b.add("a"));
        System.out.println(b.add("b"));
        System.out.println(b.add("c"));
        System.out.println(b.add("d"));
        System.out.println(b.add("345546567567"));


        System.out.println(new HashDemo().hashCode());
        System.out.println(new HashDemo().hashCode());
        System.out.println(HashDemo.hash(new HashDemo()));
        System.out.println(HashDemo.hash(new HashDemo()));


    }
}